package com.wujunshen.designpattern.creational.singleton;

import java.lang.reflect.Constructor;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

/**
 * @author frank woo(吴峻申) <br>
 *     email:<a href="mailto:frank_wjs@hotmail.com">frank_wjs@hotmail.com</a> <br>
 * @date 2021/2/16 03:37<br>
 */
@Slf4j
public class Reflection {
  @SneakyThrows
  public static void main(String[] args) {
    // 懒汉式—线程不安全 false
    log.info(
        "懒汉式—线程不安全 {}",
        destroySingleton(LazyNoSafeSingleton.class) == LazyNoSafeSingleton.getInstance());

    // 懒汉式—线程安全 方法1 false
    log.info(
        "懒汉式—线程安全 方法1 {}",
        destroySingleton(LazySafeSingleton1.class) == LazySafeSingleton1.getInstance());

    // 懒汉式—线程安全 方法2 false
    log.info(
        "懒汉式—线程安全 方法2 {}",
        destroySingleton(LazySafeSingleton2.class) == LazySafeSingleton2.getInstance());

    // 饿汉式 false
    log.info("饿汉式 {}", destroySingleton(HungrySingleton.class) == HungrySingleton.getInstance());

    // 双检锁式 false
    log.info(
        "双检锁式 {}",
        destroySingleton(LazyDoubleCheckSingleton.class) == LazyDoubleCheckSingleton.getInstance());

    // 登记式 false
    log.info("登记式 {}", destroySingleton(Singleton.class) == Singleton.getInstance());

    // 枚举 抛异常java.lang.NoSuchMethodException
    //log.info("枚举 {}", destroySingleton(SingletonEnum.class) == SingletonEnum.getInstance());

    // 枚举 抛异常java.lang.IllegalArgumentException
    log.info("枚举 {}", destroySingletonEnum(SingletonEnum.class));
  }

  /**
   * 利用反射构造新对象
   *
   * @param clazz 单例类的class
   * @param <T> 单例类
   * @return 构造的新对象
   */
  @SneakyThrows
  private static <T> T destroySingleton(Class<T> clazz) {
    // 获取类的显式构造器
    Constructor<T> construct = clazz.getDeclaredConstructor();
    // 可访问私有构造器
    construct.setAccessible(true);
    // 利用反射构造新对象
    return construct.newInstance();
  }

  @SneakyThrows
  private static <T> T destroySingletonEnum(Class<T> clazz) {
    // 获取类的显式构造器
    Constructor<T> construct = clazz.getDeclaredConstructor(String.class, int.class);
    // 可访问私有构造器
    construct.setAccessible(true);
    // 利用反射构造新对象
    return construct.newInstance("Tom", 888);
  }
}
